package com.come4loves.game.module.battle.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.come4loves.core.context.SpringContext;
import com.come4loves.core.result.Result;
import com.come4loves.core.thread.NamedThreadFactory;
import com.come4loves.game.component.listener.ActorLogoutListener;
import com.come4loves.game.constent.GameStatusCodeConstant;
import com.come4loves.game.module.battle.helper.BattlePushHelper;
import com.come4loves.game.module.battle.model.ActorCard;
import com.come4loves.game.module.battle.model.ActorTeamValue;
import com.come4loves.game.module.battle.model.BattleData;
import com.come4loves.game.module.battle.service.BattleService;
import com.come4loves.game.module.card.constant.CardType;
import com.come4loves.game.module.card.helper.CardHelper;
import com.come4loves.game.module.fight.constants.FightConst;
import com.come4loves.game.module.fight.constants.Team;
import com.come4loves.game.module.fight.model.ActorBattle;
import com.come4loves.game.module.fight.model.BattleScene;
import com.come4loves.game.module.fight.model.DeskOfCard;
import com.come4loves.game.module.fight.model.FightCard;
import com.come4loves.game.module.fight.model.MainCardArea;
import com.come4loves.game.module.fight.model.ShowCardData;

@Component
public class BattleServiceImpl implements BattleService, ActorLogoutListener {
	protected Logger LOGGER = LoggerFactory.getLogger(getClass());
	private Map<Long, BattleScene> map = new HashMap<Long, BattleScene>();

	private LinkedBlockingQueue<ActorTeamValue> matchActorIds = new LinkedBlockingQueue<ActorTeamValue>();
	private LinkedBlockingQueue<ActorTeamValue> mutiActorIds = new LinkedBlockingQueue<ActorTeamValue>();
	ExecutorService executorServicePVP;
	ExecutorService executorServiceMutiPVE;
	@PostConstruct
	private void init() {
		ThreadFactory tf = new NamedThreadFactory("match thread");
		executorServicePVP = Executors.newSingleThreadExecutor(tf);
		Runnable r = new Runnable() {

			@Override
			public void run() {
				while (true) {
					synchronized (matchActorIds) {
						if (matchActorIds.size() < 2) {
							try {
								matchActorIds.wait();
							} catch (InterruptedException e) {
								LOGGER.error("{}", e);
							}
						} else {
							ActorTeamValue actorTeamValue = matchActorIds.poll();
							ActorTeamValue actorTeamValue1 = matchActorIds.poll();
							actorTeamValue.setTeam(Team.TEAM_A);
							actorTeamValue1.setTeam(Team.TEAM_B);
							List<ActorTeamValue> actorTeamValues = new ArrayList<ActorTeamValue>();
							actorTeamValues.add(actorTeamValue);
							actorTeamValues.add(actorTeamValue1);
							BattleData bd = createBattleData(actorTeamValues);
							BattlePushHelper.pushBattleData(actorTeamValue.getActorId(), bd);
							BattlePushHelper.pushBattleData(actorTeamValue1.getActorId(), bd);
							LOGGER.debug("match success, actorId1:{}, actorId2:{}", actorTeamValue.getActorId(), actorTeamValue1.getActorId());
							initHandCard(actorTeamValue.getActorId());
						}
					}
				}

			}
		};
		executorServicePVP.execute(r);
		
		executorServiceMutiPVE = Executors.newSingleThreadExecutor(tf);
		
		Runnable r1 = new Runnable() {

			@Override
			public void run() {
				while (true) {
					synchronized (mutiActorIds) {
						if (mutiActorIds.size() < 3) {
							try {
								mutiActorIds.wait();
							} catch (InterruptedException e) {
								LOGGER.error("{}", e);
							}
						} else {
							ActorTeamValue actorTeamValue = mutiActorIds.poll();
							ActorTeamValue actorTeamValue1 = mutiActorIds.poll();
							ActorTeamValue actorTeamValue2 = mutiActorIds.poll();
							actorTeamValue.setTeam(Team.TEAM_A);
							actorTeamValue1.setTeam(Team.TEAM_A);
							actorTeamValue2.setTeam(Team.TEAM_A);
							List<ActorTeamValue> actorTeamValues = new ArrayList<ActorTeamValue>();
							ActorTeamValue actorTeamValue3 = new ActorTeamValue(actorTeamValue.getActorId(), actorTeamValue.getCardGroupId(), true);
							actorTeamValues.add(actorTeamValue);
							actorTeamValues.add(actorTeamValue1);
							actorTeamValues.add(actorTeamValue2);
							actorTeamValues.add(actorTeamValue3);
							
							
							BattleData bd = createBattleData(actorTeamValues);
							BattlePushHelper.pushBattleData(actorTeamValue.getActorId(), bd);
							BattlePushHelper.pushBattleData(actorTeamValue1.getActorId(), bd);
							BattlePushHelper.pushBattleData(actorTeamValue2.getActorId(), bd);
							LOGGER.debug("muti success, actorId1:{}, actorId2:{},actorId3:{}", actorTeamValue.getActorId(), actorTeamValue1.getActorId(), actorTeamValue2.getActorId());
							initHandCard(actorTeamValue.getActorId());
						}
					}
				}

			}
		};
		executorServiceMutiPVE.execute(r1);
	}

	private BattleData createBattleData(List<ActorTeamValue> actorTeamValues) {
		BattleScene battleScene = createBattleScene(actorTeamValues);
		Collection<ActorBattle> actorBattles = battleScene.getActorBattles();
		BattleData battleData = new BattleData();
		for (ActorBattle actorBattle : actorBattles) {
			ActorCard actorCard = new ActorCard(actorBattle.getActorId(), actorBattle.getTeam(), actorBattle.getDeskOfCard().remainCards(), actorBattle.getHandCards().values(), actorBattle
					.getShowCards().values(), actorBattle.getMainCards(), actorBattle.getCurrentMagic(), actorBattle.getMaxMagic());
			battleData.addActorCard(actorCard);
		}

		return battleData;
	}

	@Override
	public BattleData getBattleData(long actorId) {
//		BattleData battleData = new BattleData();
//		BattleScene battleScene = map.get(actorId);
//		if (battleScene != null) {
//			battleScene.destory();
//		}
//		List<ActorTeamValue> actorTeamValues = new ArrayList<ActorTeamValue>();
//		ActorTeamValue actorTeamValue = new ActorTeamValue(actorId, Team.TEAM_A, false);
//		ActorTeamValue actorTeamValue1 = new ActorTeamValue(actorId, Team.TEAM_B, true);
//		actorTeamValues.add(actorTeamValue);
//		actorTeamValues.add(actorTeamValue1);
//		battleScene = createBattleScene(actorTeamValues);
//		this.map.put(actorId, battleScene);
//		Collection<ActorBattle> actorBattles = battleScene.getActorBattles();
//		for (ActorBattle actorBattle : actorBattles) {
//			ActorCard actorCard = new ActorCard(actorBattle.getActorId(), actorBattle.getTeam(), actorBattle.getDeskOfCard().remainCards(), actorBattle.getHandCards().values(), actorBattle
//					.getShowCards().values(), actorBattle.getMainCards(), actorBattle.getCurrentMagic(), actorBattle.getMaxMagic());
//			battleData.addActorCard(actorCard);
//		}
//
//		return battleData;
		return null;
	}
	
	private BattleScene createBattleScene(List<ActorTeamValue> actorTeamValues) {
		AtomicInteger id = new AtomicInteger(1);
		List<ActorBattle> list = new ArrayList<ActorBattle>();
		for (ActorTeamValue actorTeamValue : actorTeamValues) {
			ActorBattle actorBattle = createActorBattle(actorTeamValue.getActorId(), actorTeamValue.getTeam(), id, actorTeamValue.isAi());
			list.add(actorBattle);
			
		}
		
		BattleScene battleScene = new BattleScene(list);
		
		for (ActorTeamValue actorTeamValue : actorTeamValues) {
			if (!actorTeamValue.isAi()){
				this.map.put(actorTeamValue.getActorId(), battleScene);
			}
		}
		return battleScene;
		
	}
	
	private ActorBattle createActorBattle(long actorId, Team team,  AtomicInteger idCreater, boolean ai){
		DeskOfCard<FightCard> deskOfCard = createDeskCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
		FightCard mainCard = createMainCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
		MainCardArea mainCardArea = new MainCardArea(mainCard);
		List<MainCardArea> area = new ArrayList<MainCardArea>();
		area.add(mainCardArea);
		ActorBattle actorBattle = new ActorBattle(actorId, FightConst.INIT_MAGIC, FightConst.INIT_MAGIC, deskOfCard, area, team, idCreater, ai);
		return actorBattle;
	}

//	private BattleScene getTestBattleScene(long actorId, long otherActorId) {
//		DeskOfCard<FightCard> deskOfCard1 = createDeskCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
//		DeskOfCard<FightCard> deskOfCard2 = null;
//		if (otherActorId > 0) {
//			deskOfCard2 = createDeskCard(CardHelper.getFightCardFromCardGroup(otherActorId, 1));
//		} else {
//			deskOfCard2 = createDeskCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
//		}
//		FightCard mainCard1 = createMainCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
//		FightCard mainCard2 = null;
//		if (otherActorId > 0) {
//			mainCard2 = createMainCard(CardHelper.getFightCardFromCardGroup(otherActorId, 1));
//		} else {
//			mainCard2 = createMainCard(CardHelper.getFightCardFromCardGroup(actorId, 1));
//		}
//		AtomicInteger id = new AtomicInteger(1);
//		MainCardArea mainCardArea1 = new MainCardArea(mainCard1);
//		MainCardArea mainCardArea2 = new MainCardArea(mainCard2);
//		List<MainCardArea> area1 = new ArrayList<MainCardArea>();
//		area1.add(mainCardArea1);
//		List<MainCardArea> area2 = new ArrayList<MainCardArea>();
//		area2.add(mainCardArea2);
//
//		ActorBattle actorBattle1 = new ActorBattle(actorId, FightConst.INIT_MAGIC, FightConst.INIT_MAGIC, deskOfCard1, area1, Team.TEAM_A, id);
//		ActorBattle actorBattle2 = new ActorBattle(otherActorId, FightConst.INIT_MAGIC, FightConst.INIT_MAGIC, deskOfCard2, area2, Team.TEAM_B, id);
//		List<ActorBattle> list = new ArrayList<ActorBattle>();
//		list.add(actorBattle1);
//		list.add(actorBattle2);
//		BattleScene battleScene = null;
//		if (otherActorId < 0) {
//			battleScene = new BattleScene(true,list);
//		} else {
//			battleScene = new BattleScene(false,list);
//		}
//		return battleScene;
//	}

	private DeskOfCard<FightCard> createDeskCard(List<FightCard> all) {
		List<FightCard> list = new ArrayList<FightCard>();
		for (FightCard fightCard : all) {
			if (!fightCard.getCardType().equals(CardType.GENERAL)) {
				list.add(fightCard);
			}
		}
		return new DeskOfCard<FightCard>(list);
	}

	private FightCard createMainCard(List<FightCard> all) {
		for (FightCard fightCard : all) {
			if (fightCard.getCardType().equals(CardType.GENERAL)) {
				return fightCard;
			}
		}
		return null;
	}

	public static void main(String[] args) {
		BattleServiceImpl impl = (BattleServiceImpl) SpringContext.getBean(BattleServiceImpl.class);
		impl.getBattleData(1);
	}

	@Override
	public Result useCard(long actorId, ShowCardData data) {
		BattleScene battleScene = map.get(actorId);
		if (battleScene == null || battleScene.isEnd()) {
			return Result.valueOf(GameStatusCodeConstant.BATTLE_NOT_EXSIT);
		}
		return battleScene.useCard(actorId, data);

	}

	@Override
	public Result roundEnd(long actorId) {
		BattleScene battleScene = map.get(actorId);
		if (battleScene == null || battleScene.isEnd()) {
			return Result.valueOf(GameStatusCodeConstant.BATTLE_NOT_EXSIT);
		}
		battleScene.roundEnd(actorId);
		return Result.valueOf();
	}

	private void initHandCard(long actorId) {
		BattleScene battleScene = map.get(actorId);
		if (battleScene == null) {
			return;
		}

		battleScene.getCards();
	}

	@Override
	public Result changeCard(long actorId, List<Integer> idList) {
		BattleScene battleScene = map.get(actorId);
		if (battleScene == null) {
			return Result.valueOf(GameStatusCodeConstant.BATTLE_NOT_EXSIT);
		}

		return battleScene.changeCard(actorId, idList);
	}

	@Override
	public void enterPVP(long actorId, int cardGroupId) {
		synchronized (this.matchActorIds) {
			ActorTeamValue actorTeamValue = new ActorTeamValue(actorId, cardGroupId, false);
			this.matchActorIds.add(actorTeamValue);
			this.matchActorIds.notifyAll();
		}
	}
	
	@Override
	public void enterMutiPVE(long actorId, int cardGroupId) {
		synchronized (this.mutiActorIds) {
			ActorTeamValue actorTeamValue = new ActorTeamValue(actorId, cardGroupId, false);
			this.mutiActorIds.add(actorTeamValue);
			this.mutiActorIds.notifyAll();
		}
	}
	
	@Override
	public void enterPVE(long actorId, int cardGroupId) {
		ActorTeamValue actorTeamValue = new ActorTeamValue(actorId, cardGroupId, false);
		actorTeamValue.setTeam(Team.TEAM_A);
		ActorTeamValue actorTeamValue1 = new ActorTeamValue(actorId, cardGroupId, true);
		actorTeamValue1.setTeam(Team.TEAM_B);
		List<ActorTeamValue> actorTeamValues = new ArrayList<ActorTeamValue>();
		actorTeamValues.add(actorTeamValue);
		actorTeamValues.add(actorTeamValue1);
		BattleData bd = createBattleData(actorTeamValues);
		BattlePushHelper.pushBattleData(actorTeamValue.getActorId(), bd);
		initHandCard(actorId);
		
	}

	@Override
	public void onLogout(long actorId) {
		this.map.remove(actorId);
	}

}
